package dao;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.List;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import persistence.DAOFactory;
import persistence.DAOFactoryJdbcTestImpl;
import persistence.LibraryLocation;
import persistence.LibraryLocationDAO;
import persistence.Subscription;
import persistence.SubscriptionDAO;
import persistence.Supplier;
import persistence.SupplierDAO;
import persistence.exception.DAOException;
import persistence.util.TestConnectionProvider;

public class SubscriptionDAOTest {

	private static SubscriptionDAO subscriptionDAO;
	private static LibraryLocationDAO libraryLocationDAO;
	private static SupplierDAO supplierDAO;
	private static SqlProcessor sqlProcessor;
	private Boolean changedDB = Boolean.FALSE;
	
	@BeforeClass
	public static void initializeTests() throws DAOException {
		System.out.println("starting BEFORE CLASS");
		sqlProcessor = new SqlProcessor(
				new TestConnectionProvider());
		DAOFactory factory = new DAOFactoryJdbcTestImpl();
		subscriptionDAO = factory.getSubscriptionDAO();
		libraryLocationDAO = factory.getLibraryLocationDAO();
		supplierDAO = factory.getSupplierDAO();
		initDB();
		System.out.println("finishing BEFORE CLASS");
	}
	
	@Before
	public void setUp() {
	}
	
	@Test
	public void findSubscription() throws DAOException {
		Subscription arbeitsrecht = subscriptionDAO.findSubscription(2);
		assertEquals(arbeitsrecht.getPeriodical().getTitle(), "Arbeitsrecht");
	}
	
	@Test//(expected=DAOException.class)
	public void checkGetAllSubscriptionsAsc() throws DAOException {
		assertTrue(subscriptionDAO.getAllSubscriptionsAsc().size()==3);
	}
	
	@Test
	public void checkGetAllSubscriptionsByTitle() throws DAOException {
		List<Subscription> subscriptions = subscriptionDAO.getAllSubscriptionsByTitle("Betriebswirtschaftliche Zeitung");
		assertTrue(subscriptions.size()==1);
		assertEquals(subscriptions.get(0).getPeriodical().getTitle(), "Betriebswirtschaftliche Zeitung");
		subscriptions = subscriptionDAO.getAllSubscriptionsByTitle("a");
		assertTrue(subscriptions.size()==2);
	}
	
	@Test
	public void getAllSubscriptionsForLocation() throws DAOException {
		LibraryLocation location = libraryLocationDAO.find(2);
		List<Subscription> subscriptions = subscriptionDAO.getAllSubscriptionsForLocation(location);
		Boolean allLocationsMatch = Boolean.TRUE;
		for (Subscription s : subscriptions) {
			if (!s.getLocation().equals(location)) {
				allLocationsMatch = Boolean.FALSE;
			}
		}
		assertTrue(allLocationsMatch);
	}
	
	/** This test indicates the problem, that UNIQUE (lieferanten_id, abo_id)
	 *  is fulfilled, when abo_nr (subscriptionNo) is NULL */
	@Test
	public void saveSubscriptionProblem() throws DAOException {
		List<Subscription> allSubscriptions = subscriptionDAO.getAllSubscriptionsAsc();
		int oldSize = allSubscriptions.size();
		//subscriptionNo and supplier need to be unique
		Subscription s = allSubscriptions.get(1);
		s.setSubscriptionNo(null);
		subscriptionDAO.saveSubscription(s);
		int newSize = subscriptionDAO.getAllSubscriptionsAsc().size();
		assertTrue(newSize==(++oldSize));
		changedDB = Boolean.TRUE;
	}
	
	@Test
	public void saveSubscription() throws DAOException {
		Subscription newSubscription = subscriptionDAO.findSubscription(1);
		//supplier with id 3 is never used in the test data
		Supplier supplier = supplierDAO.find(3);
		newSubscription.setSupplier(supplier);
		newSubscription.setId(0);
		Subscription savedSubscription = subscriptionDAO.saveSubscription(newSubscription);
		//shows that DAO assigned new id to the new Subscription:
		assertTrue(savedSubscription.getId()!=0);
		assertEquals(newSubscription, savedSubscription);
		changedDB = Boolean.TRUE;
	}
	
	@Test(expected=DAOException.class)
	public void saveSubscriptionFails() throws DAOException {
		Subscription newSubscription = subscriptionDAO.findSubscription(1);
		//subscriptionNo and supplier need to be unique	
		newSubscription.setSubscriptionNo(null);
		//violates NOT NULL constraint for "lieferanten_id" and should thus throw DAOException
		newSubscription.setSupplier(null);
		Subscription savedSubscription = subscriptionDAO.saveSubscription(newSubscription);
		assertEquals(newSubscription, savedSubscription);
	}
	
	@Test
	public void updateSubscription() throws DAOException {
		Subscription arbeitsrecht = subscriptionDAO.findSubscription(3);
		String oldNotes = arbeitsrecht.getNotes();
		String newNotes = oldNotes + " updated";
		Subscription newArbeitsrecht = arbeitsrecht;
		newArbeitsrecht.setNotes(newNotes);
		subscriptionDAO.updateSubscription(newArbeitsrecht);
		assertEquals(subscriptionDAO.findSubscription(3).getNotes(), newNotes);
		changedDB = Boolean.TRUE;
	}	
	
	@After
	public void tearDown() {
		if (changedDB) {
			sqlProcessor.executeSqlScript("scripts/db_schema_hsqldb.sql");
			sqlProcessor.executeSqlScript("scripts/test_data_hsqldb.sql");
			changedDB = Boolean.FALSE;
			System.out.println("AFTER");
		}
	}
	
	@AfterClass
	public static void restoreDBstate() {
		System.out.println("Starting AFTER CLASS");
		restoreDB();
		System.out.println("Finishing AFTER CLASS");
	}
	
	protected static void initDB() {

		sqlProcessor.executeSqlScript("scripts/db_schema_hsqldb.sql");
		sqlProcessor.executeSqlScript("scripts/test_data_hsqldb.sql");
	}
	
	protected static void restoreDB() {
		initDB();
	}
}
